//* global window */
import { h } from './element';
import Suggest from './suggest';
import Datepicker from './datepicker';
import { cssPrefix } from '../config';
// import { mouseMoveUp } from '../event';

function resetTextareaSize() {
    const { inputText } = this;
    if (!/^\s*$/.test(inputText)) {
        const {
            textlineEl,
            textEl,
            areaOffset,
        } = this;
        const txts = inputText.split('\n');
        const maxTxtSize = Math.max(...txts.map(it => it.length));
        const tlOffset = textlineEl.offset();
        const fontWidth = tlOffset.width / inputText.length;
        const tlineWidth = (maxTxtSize + 1) * fontWidth + 5;
        const maxWidth = this.viewFn().width - areaOffset.left - fontWidth;
        let h1 = txts.length;
        if (tlineWidth > areaOffset.width) {
            let twidth = tlineWidth;
            if (tlineWidth > maxWidth) {
                twidth = maxWidth;
                h1 += parseInt(tlineWidth / maxWidth, 10);
                h1 += (tlineWidth % maxWidth) > 0 ? 1 : 0;
            }
            textEl.css('width', `${twidth}px`);
        }
        h1 *= this.rowHeight;
        if (h1 > areaOffset.height) {
            textEl.css('height', `${h1}px`);
        }
    }
}

function insertText({ target }, itxt) {
    const { value, selectionEnd } = target;
    const ntxt = `${value.slice(0, selectionEnd)}${itxt}${value.slice(selectionEnd)}`;
    target.value = ntxt;
    target.setSelectionRange(selectionEnd + 1, selectionEnd + 1);

    this.inputText = ntxt;
    this.textlineEl.html(ntxt);
    resetTextareaSize.call(this);
}

function keydownEventHandler(evt) {
    const { keyCode, altKey } = evt;
    if (keyCode !== 13 && keyCode !== 9) evt.stopPropagation();
    if (keyCode === 13 && altKey) {
        insertText.call(this, evt, '\n');
        evt.stopPropagation();
    }
    if (keyCode === 13 && !altKey) evt.preventDefault();
}

function inputEventHandler(evt) {
    const v = evt.target.value;
    // console.log(evt, 'v:', v);
    const { suggest, textlineEl, validator } = this;
    const { cell } = this;
    if (cell !== null) {
        if (('editable' in cell && cell.editable === true) || (cell.editable === undefined)) {
            this.inputText = v;
            if (validator) {
                if (validator.type === 'list') {
                    suggest.search(v);
                } else {
                    suggest.hide();
                }
            } else {
                const start = v.lastIndexOf('=');
                if (start !== -1) {
                    suggest.search(v.substring(start + 1));
                } else {
                    suggest.hide();
                }
            }
            textlineEl.html(v);
            resetTextareaSize.call(this);
            this.change('input', v);
        } else {
            evt.target.value = '';
        }
    } else {
        this.inputText = v;
        if (validator) {
            if (validator.type === 'list') {
                suggest.search(v);
            } else {
                suggest.hide();
            }
        } else {
            const start = v.lastIndexOf('=');
            if (start !== -1) {
                suggest.search(v.substring(start + 1));
            } else {
                suggest.hide();
            }
        }
        textlineEl.html(v);
        resetTextareaSize.call(this);
        this.change('input', v);
    }
}

function setTextareaRange(position) {
    const { el } = this.textEl;
    setTimeout(() => {
        el.focus();
        el.setSelectionRange(position, position);
    }, 0);
}

function setText(text, position) {
    const { textEl, textlineEl } = this;
    // firefox bug
    textEl.el.blur();

    textEl.val(text);
    textlineEl.html(text);
    setTextareaRange.call(this, position);
}

function suggestItemClick(it) {
    const { inputText, validator } = this;
    let position = 0;
    if (validator && validator.type === 'list') {
        this.inputText = it;
        position = this.inputText.length;
    } else {
        const start = inputText.lastIndexOf('=');
        const sit = inputText.substring(0, start + 1);
        let eit = inputText.substring(start + 1);
        if (eit.indexOf(')') !== -1) {
            eit = eit.substring(eit.indexOf(')'));
        } else {
            eit = '';
        }
        this.inputText = `${sit + it.key}(`;
        // console.log('inputText:', this.inputText);
        position = this.inputText.length;
        this.inputText += `)${eit}`;
    }
    setText.call(this, this.inputText, position);
}

function resetSuggestItems() {
    this.suggest.setItems(this.formulas);
}

function dateFormat(d) {
    let month = d.getMonth() + 1;
    let date = d.getDate();
    if (month < 10) month = `0${month}`;
    if (date < 10) date = `0${date}`;
    return `${d.getFullYear()}-${month}-${date}`;
}

export default class Editor {
    constructor(formulas, viewFn, rowHeight) {
        this.viewFn = viewFn;
        this.rowHeight = rowHeight;
        this.formulas = formulas;
        this.suggest = new Suggest(formulas, (it) => {
            suggestItemClick.call(this, it);
        });
        this.datepicker = new Datepicker();
        this.datepicker.change((d) => {
            // console.log('d:', d);
            this.setText(dateFormat(d));
            this.clear();
        });
        this.areaEl = h('div', `${cssPrefix}-editor-area`)
            .children(
                this.textEl = h('textarea', '')
                .on('input', evt => inputEventHandler.call(this, evt))
                .on('paste.stop', () => {})
                .on('keydown', evt => keydownEventHandler.call(this, evt)),
                this.textlineEl = h('div', 'textline'),
                this.suggest.el,
                this.datepicker.el,
            )
            .on('mousemove.stop', () => {})
            .on('mousedown.stop', () => {});
        this.el = h('div', `${cssPrefix}-editor`)
            .child(this.areaEl).hide();
        this.suggest.bindInputEvents(this.textEl);

        this.areaOffset = null;
        this.freeze = { w: 0, h: 0 };
        this.cell = null;
        this.inputText = '';
        this.change = () => {};
    }

    setFreezeLengths(width, height) {
        this.freeze.w = width;
        this.freeze.h = height;
    }

    clear() {
        // const { cell } = this;
        // const cellText = (cell && cell.text) || '';
        if (this.inputText !== '') {
            this.change('finished', this.inputText);
        }
        this.cell = null;
        this.areaOffset = null;
        this.inputText = '';
        this.el.hide();
        this.textEl.val('');
        this.textlineEl.html('');
        resetSuggestItems.call(this);
        this.datepicker.hide();
    }

    setOffset(offset, suggestPosition = 'top') {
        const {
            textEl,
            areaEl,
            suggest,
            freeze,
            el,
        } = this;
        if (offset) {
            this.areaOffset = offset;
            const {
                left,
                top,
                width,
                height,
                l,
                t,
            } = offset;
            // console.log('left:', left, ',top:', top, ', freeze:', freeze);
            const elOffset = { left: 0, top: 0 };
            // top left
            if (freeze.w > l && freeze.h > t) {
                //
            } else if (freeze.w < l && freeze.h < t) {
                elOffset.left = freeze.w;
                elOffset.top = freeze.h;
            } else if (freeze.w > l) {
                elOffset.top = freeze.h;
            } else if (freeze.h > t) {
                elOffset.left = freeze.w;
            }
            el.offset(elOffset);
            areaEl.offset({ left: left - elOffset.left - 0.8, top: top - elOffset.top - 0.8 });
            textEl.offset({ width: width - 9 + 0.8, height: height - 3 + 0.8 });
            const sOffset = { left: 0 };
            sOffset[suggestPosition] = height;
            suggest.setOffset(sOffset);
            suggest.hide();
        }
    }

    setCell(cell, validator) {
        // console.log('::', validator);
        const { el, datepicker, suggest } = this;
        el.show();
        this.cell = cell;
        const text = (cell && cell.text) || '';
        this.setText(text);

        this.validator = validator;
        if (validator) {
            const { type } = validator;
            if (type === 'date') {
                datepicker.show();
                if (!/^\s*$/.test(text)) {
                    datepicker.setValue(text);
                }
            }
            if (type === 'list') {
                suggest.setItems(validator.values());
                suggest.search('');
            }
        }
    }

    setText(text) {
        this.inputText = text;
        // console.log('text>>:', text);
        setText.call(this, text, text.length);
        resetTextareaSize.call(this);
    }
}